/*******************************************************************************
 * @file    bsp_spi.c
 * @brief   SPI Interface drivers
 *
 * @version 1.0.0
 *******************************************************************************
 * @license Refer License or other description Docs
 * @author  Felix
 ******************************************************************************/
#include "cpu/bsp_spi.h"
#include "cpu/bsp_clock.h"
#include <string.h>

/**
 * GPIO config for SPI
 */
static void BSP_SPI_PortInit(BSP_SPI_TypeDef *ptr)
{
    stc_gpio_cfg_t gpioCfg;
    DDL_ZERO_STRUCT(gpioCfg);

    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);

    gpioCfg.enDir = GpioDirOut;
    Gpio_Init(ptr->gpio, ptr->nss, &gpioCfg);    /* CS */
    Gpio_SetAfMode(ptr->gpio, ptr->nss, ptr->af);

    Gpio_Init(ptr->gpio, ptr->sck, &gpioCfg);      /* SCK */
    Gpio_SetAfMode(ptr->gpio, ptr->sck, ptr->af);

    Gpio_Init(ptr->gpio, ptr->mosi,  &gpioCfg);   /* MOSI */
    Gpio_SetAfMode(ptr->gpio, ptr->mosi, ptr->af);

    gpioCfg.enDir = GpioDirIn;
    Gpio_Init(ptr->gpio, ptr->miso, &gpioCfg);    /* MISO */
    Gpio_SetAfMode(ptr->gpio, ptr->miso, ptr->af);
}

/****
Global Functions
****/

/**
 * SPI Initialization
 */
void BSP_SPI_Init(BSP_SPI_TypeDef *ptr)
{
    M0P_SPI_TypeDef* enCh = M0P_SPI0;

    stc_spi_cfg_t  spiCfg;

    DDL_ZERO_STRUCT(spiCfg);

    /* Enabling clock */
    if(BSP_SPI1 == ptr->idx){
        enCh = M0P_SPI1;
        Sysctrl_SetPeripheralGate(SysctrlPeripheralSpi1, TRUE);
    } else {
        Sysctrl_SetPeripheralGate(SysctrlPeripheralSpi0, TRUE);
    }

    /* Set GPIO config for SPI */
    BSP_SPI_PortInit(ptr);

    /* SPI config to master */
    spiCfg.enCPHA = SpiMskCphafirst;
    spiCfg.enCPOL = SpiMskcpollow;
    spiCfg.enSpiMode = SpiMskMaster;
    spiCfg.enPclkDiv = SpiClkMskDiv2;

    Spi_SetCS(enCh, TRUE);

    Spi_Init(enCh, &spiCfg);

    return;
}

void BSP_SPI_DeInit(BSP_SPI_IDX spiIdx)
{
    M0P_SPI_TypeDef* enCh = M0P_SPI0;
    if(BSP_SPI1 == spiIdx){
        enCh = M0P_SPI1;
        Sysctrl_SetPeripheralGate(SysctrlPeripheralSpi1, FALSE);
    } else {
        Sysctrl_SetPeripheralGate(SysctrlPeripheralSpi0, FALSE);
    }
    enCh->DATA  = 0x00;
    enCh->STAT  = 0x00;
    enCh->CR  = 0x00;

    if(BSP_SPI1 == spiIdx){
        EnableNvic(SPI1_IRQn,IrqLevel3,FALSE);
    } else {
        EnableNvic(SPI0_IRQn,IrqLevel3,FALSE);
    }
}

bool BSP_SPI_Write(BSP_SPI_IDX spiIdx, uint8_t addr, const uint8_t* data, uint32_t len)
{
    M0P_SPI_TypeDef* enCh = M0P_SPI0;
    uint32_t i = 0;
    bool success = true;

    if ((NULL == data) || (0 == len)) {
        return false;
    }

    if(BSP_SPI1 == spiIdx){
        enCh = M0P_SPI1;
    }

    Spi_SetCS(enCh, FALSE);

    while(Spi_GetStatus(enCh, SpiTxe) == FALSE);
    Spi_SendData(enCh, addr);

    for(i = 0; i < len; i++){
        while(Spi_GetStatus(enCh, SpiTxe) == FALSE);
        Spi_SendData(enCh, data[i]);
    }
    Spi_SetCS(enCh, TRUE);

    return success;
}

bool BSP_SPI_ReadWrite(BSP_SPI_IDX spiIdx, uint8_t addr, uint8_t* data, uint32_t len)
{
    M0P_SPI_TypeDef* enCh = M0P_SPI0;
    uint32_t i = 0;
    bool success = true;

    if(BSP_SPI1 == spiIdx){
        enCh = M0P_SPI1;
    }

    Spi_SetCS(enCh, FALSE);

    while(Spi_GetStatus(enCh, SpiTxe) == FALSE);
    Spi_SendData(enCh, addr);

    for(i = 0; i < len; i++){
        while(Spi_GetStatus(enCh, SpiTxe) == FALSE);
        Spi_SendData(enCh, 0);
        BSP_ClockdelayUs(200);
        while(Spi_GetStatus(enCh, SpiRxne) == FALSE);
        data[i] = Spi_ReceiveData(enCh);
    }
    Spi_SetCS(enCh, TRUE);

    return success;
}

